// 垃圾回收机制  GC
// JS中内存的分配的回收都是自动完成的，内存在不使用的时候会被垃圾回收器自动回收

/** 内存的生命周期
 * 内存分配：当我们声明变量、函数、对象的时候，系统会自动为他们分配内存
 * 内存使用：读写内存，也就是使用变量、函数
 * 内存回收：使用完毕，由：垃圾回收器自动回收不再使用的内存
 * 
 * 全局变量一般不会回收（关闭页面时回收）
 * 一般情况下局部变量的值，不用了，会被自动回收掉
 */
// 内存泄漏：程序中分配的内存由于某种原因程序未释放或无法释放叫做内存泄漏

/**
 * 引用计数法（2012年之后已经被淘汰了）
 * 最初级的垃圾收集算法：对象有没有其他对象引用到它，如果没有引用指向该对象，对象将被垃圾回收机制回收
 * 总结：引用计数法就是数堆内存中对象被引用了多少次，如果只有 0 次 就会被回收
 */

let obj = {
    name:'zxc'   // 创建一个对象，被 obj 变量所引用，计数为 1 
}
let obj2 = obj  // obj2 变量是第二个 对该对象的引用，计数为 2 

obj = null // 该对象的原始引用  obj 已经没有了，计数为 1

obj2 = null //此时对象所有引用都没有了，计数 0 垃圾回收机制回收该对象


// 致命缺点：循环引用
function fn(){
    let o1 = {
        name:'刻晴'
    }
    let o2 = {
        name:'甘雨'
    }
    o1.friend = o2
    o2.friend = o1
    console.log(o1,o2)
}
fn()
/**
 * 由于 o1  和  o2  互相引用着对方，哪怕没有变量引用他两了，在内存中依然不会被销毁，因为引用计数是  1
 * 所以  引用计数法  极易导致内存泄漏
 */


/**
 * 标记清楚法：假定全局作为根，一层一层往局部去标记所有对象，打完标记之后，如果有些对象没有标记，就会被清除
 */
// 分代收集（Generational collection）—— 对象被分成两组：“新的”和“旧的”。在典型的代码中，许多对象的生命周期都很短：它们出现、完成它们的工作并很快死去，因此在这种情况下跟踪新对象并将其从内存中清除是有意义的。那些长期存活的对象会变得“老旧”，并且被检查的频次也会降低。
// 增量收集（Incremental collection）—— 如果有许多对象，并且我们试图一次遍历并标记整个对象集，则可能需要一些时间，并在执行过程中带来明显的延迟。因此，引擎将现有的整个对象集拆分为多个部分，然后将这些部分逐一清除。这样就会有很多小型的垃圾收集，而不是一个大型的。这需要它们之间有额外的标记来追踪变化，但是这样会带来许多微小的延迟而不是一个大的延迟。
// 闲时收集（Idle-time collection）—— 垃圾收集器只会在 CPU 空闲时尝试运行，以减少可能对代码执行的影响。